﻿using System;
using System.Configuration;
using System.Web;
using System.Text;
using System.Xml;
using Telerik.Cms;
using Telerik.Cms.Data;
using Telerik.Cms.Engine;

using Telerik.News;
using Telerik.Blogs;
using Telerik.Events;
using System.Collections.Generic;

namespace SelArom.Net.Sitefinity.HttpHandlers
{
	/// <summary>
	/// HttpHandler for creating a Google XML SiteMap from the Sitefinity SiteMap
	/// </summary>
	public class SiteMap : IHttpHandler
	{
		public void ProcessRequest(HttpContext context)
		{
			try
			{
				var response = context.Response;
				response.ContentType = "text/xml";

				var writer = new XmlTextWriter(response.OutputStream, Encoding.UTF8) { Formatting = Formatting.Indented };
				writer.WriteStartDocument();
				writer.WriteStartElement("urlset");
				writer.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
				writer.WriteAttributeString("xsi:schemaLocation", "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd");
				writer.WriteAttributeString("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9");

				var vars = HttpContext.Current.Request.ServerVariables;
				var now = DateTime.Now;

				// append pages
				var pages = new GetCmsPages();
				pages.LoadAll();
				foreach (var page in pages)
				{
					// skip hidden and invalid pages and groups
					if (page.Status != PageStatus.Published || page.DenyAnonymous || page.DenyIndexing || page.PageType == CmsPageType.Group) continue;

					var protocol = page.RequireSSL ? "https://" : "http://";
					var link = protocol + vars["SERVER_NAME"] + Port(vars["SERVER_PORT"]);
					writer.WriteStartElement("url");
					writer.WriteElementString("loc", link + page.DefaultUrl.Url.Substring(1).ToLower());
					writer.WriteElementString("lastmod", GetLastMod(page.DateModified));
					writer.WriteElementString("changefreq", GetChangeFreq(page.DateModified));
					writer.WriteElementString("priority", "0.5");
					writer.WriteEndElement();
				}

				// adjust url for news
				var host = "http://" + vars["SERVER_NAME"] + Port(vars["SERVER_PORT"]);
				foreach (IContent newsItem in new NewsManager(NewsManager.DefaultContentProvider).Content.GetContent())
				{
					// only include published items
					if (newsItem.Status != ContentStatus.Published) continue;

					// appkey must be present to continue
					var expDate = Convert.ToDateTime(newsItem.GetMetaData("Expiration_Date"));
					var newsUrl = expDate > now
									? ConfigurationManager.AppSettings[NewsManager.DefaultContentProvider + "Url"]
									: ConfigurationManager.AppSettings["Archive"];

					if (string.IsNullOrEmpty(newsUrl)) break;
					var fullUrl = string.Format("{0}{1}{2}.aspx", host, newsUrl, newsItem.Url.ToLower());

					writer.WriteStartElement("url");
					writer.WriteElementString("loc", fullUrl);
					writer.WriteElementString("lastmod", newsItem.DateModified.ToString("yyyy-MM-ddThh:mm:sszzzz"));
					writer.WriteElementString("changefreq", "monthly");
					writer.WriteElementString("priority", "0.5");
					writer.WriteEndElement();
				}


				// adjust for events, only get next 2 months for now
				foreach (IEvent eventItem in new EventsManager(EventsManager.DefaultContentProvider).GetEvents(DateTime.Now, DateTime.Now.AddMonths(2), "", ContentStatus.Published))
				{
					// only include published items
					if (eventItem.ContentItem.Status != ContentStatus.Published) continue;

					// appkey must be present to continue
					var evUrl = ConfigurationManager.AppSettings[EventsManager.DefaultContentProvider + "Url"];
					if (string.IsNullOrEmpty(evUrl)) break;
					var fullUrl = string.Format("{0}{1}{2}.aspx", host, evUrl, eventItem.ContentItem.Url.ToLower());

					writer.WriteStartElement("url");
					writer.WriteElementString("loc", fullUrl);
					writer.WriteElementString("lastmod", eventItem.End.ToString("yyyy-MM-ddThh:mm:sszzzz"));
					writer.WriteElementString("changefreq", "monthly");
					writer.WriteElementString("priority", "0.5");
					writer.WriteEndElement();
				}

				// now blogs
				var blogMgr = new BlogManager(BlogManager.DefaultContentProvider);
				var blogs = blogMgr.GetBlogs();
				var ids = new List<Guid>();
				foreach (IBlog blog in blogs)
					ids.Add(blog.ID);

				foreach (IContent post in blogMgr.GetPosts("Publication_Date DESC", ids.ToArray()))
				{
					// only include published items
					if (post.Status != ContentStatus.Published) continue;

					// appkey must be present to continue
					var evUrl = ConfigurationManager.AppSettings[BlogManager.DefaultContentProvider + "Url"];
					if (string.IsNullOrEmpty(evUrl)) break;
					var fullUrl = string.Format("{0}{1}{2}.aspx", host, evUrl, post.Url.ToLower());

					writer.WriteStartElement("url");
					writer.WriteElementString("loc", fullUrl);
					writer.WriteElementString("lastmod", post.DateModified.ToString("yyyy-MM-ddThh:mm:sszzzz"));
					writer.WriteElementString("changefreq", "monthly");
					writer.WriteElementString("priority", "0.5");
					writer.WriteEndElement();
				}

				// generic content items
				var mgr = new ContentManager(ContentManager.DefaultProviderName);
				foreach (IContent contentItem in mgr.GetContent())
				{
					// only include published items
					if (contentItem.Status != ContentStatus.Published) continue;

					// appkey must be present to continue
					var cntUrl = ConfigurationManager.AppSettings[ContentManager.DefaultProviderName + "Url"];
					if (string.IsNullOrEmpty(cntUrl)) break;
					var fullUrl = string.Format("{0}{1}{2}.aspx", host, cntUrl, contentItem.Url.ToLower());

					writer.WriteStartElement("url");
					writer.WriteElementString("loc", fullUrl);
					writer.WriteElementString("lastmod", contentItem.DateModified.ToString("yyyy-MM-ddThh:mm:sszzzz"));
					writer.WriteElementString("changefreq", "monthly");
					writer.WriteElementString("priority", "0.5");
					writer.WriteEndElement();
				}

				writer.WriteEndElement();
				writer.WriteEndDocument();
				writer.Flush();

				response.Flush();
				writer.Flush();
			}

			catch (Exception ex)
			{
				// TODO: Log error
				context.Response.Write(ex.ToString());
			}

		}

		public string Port(string port)
		{
			return (port == "80" || port == "443") ? "" : ":" + port;
		}

		public bool IsReusable
		{
			get { return true; }
		}

		private string GetLastMod(DateTime modified)
		{
			try
			{
				return modified.ToString("yyyy-MM-ddThh:mm:sszzzz");
			}
			catch
			{
				// TODO: log error
				return DateTime.Now.ToString("yyyy-MM-ddThh:mm:sszzzz");
			}
		}

		private string GetChangeFreq(DateTime modified)
		{

			try
			{
				string retval;
				var intervalLong = (DateTime.Now - modified).Days;

				if (intervalLong <= 1)
					retval = "daily";
				else if (intervalLong <= 7 & intervalLong > 1)
					retval = "daily";
				else if (intervalLong <= 30 & intervalLong > 7)
					retval = "weekly";
				else if (intervalLong <= 30 & intervalLong > 365)
					retval = "weekly";
				else
					retval = "monthly";

				return retval;
			}
			catch
			{
				// TODO: log error
				return "monthly";
			}
		}
	}
}